package com.aim.analysis.excel;

import com.aim.analysis.artifact.AbstractArtifact;
import com.aim.analysis.artifact.ArtifactSubFolder;
import com.aim.analysis.questionnaire.QValueExtractor;
import com.aim.analysis.records.*;
import com.aim.util.ListUtil;
import com.aim.util.filters.ChainFilter;
import com.aim.util.filters.FilterUtil;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static com.aim.analysis.questionnaire.QValueExtractor.*;
import static com.aim.analysis.records.GameValueExtractor.*;

/**
 * User: Avraham Shvartzon
 * Date: 9/12/14
 */
public class DemographicStatisticReport extends AbstractArtifact {

    private String fileSuffix;
    private ArrayList<ChainFilter<Hit>> filters;
    private List<HitWrapperExtractor<?, ? extends Number>> demographicExtractors;
    private List<HitWrapperExtractor<?, ? extends Number>> gameExtractors;

    public DemographicStatisticReport(String fileSuffix) {
        this.fileSuffix = fileSuffix;
        init();
    }

    private void init() {
        filters = new ArrayList<ChainFilter<Hit>>();
        filters.add(ChainFilter.createFilter(f_all));
        filters.add(ChainFilter.createFilter(f_female));
        filters.add(ChainFilter.createFilter(f_male));

        filters.add(ChainFilter.createFilter(f_age_L_30));
        filters.add(ChainFilter.createFilter(f_age_L_30, f_female));
        filters.add(ChainFilter.createFilter(f_age_L_30, f_male));
        filters.add(ChainFilter.createFilter(f_age_SE_30));
        filters.add(ChainFilter.createFilter(f_age_SE_30, f_female));
        filters.add(ChainFilter.createFilter(f_age_SE_30, f_male));

        filters.add(ChainFilter.createFilter(f_minorOnly));
        filters.add(ChainFilter.createFilter(f_minorOnly, f_female));
        filters.add(ChainFilter.createFilter(f_minorOnly, f_male));
        filters.add(ChainFilter.createFilter(f_minorOnly, f_age_L_30));
        filters.add(ChainFilter.createFilter(f_minorOnly, f_age_L_30, f_female));
        filters.add(ChainFilter.createFilter(f_minorOnly, f_age_L_30, f_male));
        filters.add(ChainFilter.createFilter(f_minorOnly, f_age_SE_30));
        filters.add(ChainFilter.createFilter(f_minorOnly, f_age_SE_30, f_female));
        filters.add(ChainFilter.createFilter(f_minorOnly, f_age_SE_30, f_male));

        filters.add(ChainFilter.createFilter(f_maintenanceToken));
        filters.add(ChainFilter.createFilter(f_maintenanceToken, f_female));
        filters.add(ChainFilter.createFilter(f_maintenanceToken, f_male));
        filters.add(ChainFilter.createFilter(f_maintenanceToken, f_age_L_30));
        filters.add(ChainFilter.createFilter(f_maintenanceToken, f_age_L_30, f_female));
        filters.add(ChainFilter.createFilter(f_maintenanceToken, f_age_L_30, f_male));
        filters.add(ChainFilter.createFilter(f_maintenanceToken, f_age_SE_30));
        filters.add(ChainFilter.createFilter(f_maintenanceToken, f_age_SE_30, f_female));
        filters.add(ChainFilter.createFilter(f_maintenanceToken, f_age_SE_30, f_male));


        initValueExtractors();
    }

    private void initValueExtractors() {
        demographicExtractors = new ArrayList<HitWrapperExtractor<?, ? extends Number>>();

        add(female);
        add(male);
        add(enjoyGame);
        add(performanceSelfAssessment);
        add(alertFrequency_int);
        add(setFrequency_int);
        add(maintenanceAlertsHelpful);
        add(takeRisks);


        add(false, maintenance);
        add(false, minor);
        add(false, moderate);
        add(false, severe);
        add(false, netScore);
        add(false, calculatedScore2);
    }

    private void add(QValueExtractor<Integer> qExtractor) {
        demographicExtractors.add(new HitWrapperExtractor(HitWrapperExtractor.qAdapter, qExtractor));
    }

    private void add(boolean gameWithAlertOnly, GameValueExtractor<? extends Number> gameValueExtractor) {

            demographicExtractors.add(new HitWrapperExtractor(
                    gameValueExtractor.getName() + "_GA",HitWrapperExtractor.alertGameAdapter, gameValueExtractor));
        if (!gameWithAlertOnly){
            demographicExtractors.add(new HitWrapperExtractor(
                    gameValueExtractor.getName() + "_G_WO_A", HitWrapperExtractor.woAlertGameAdapter, gameValueExtractor));
        }
    }


    private ArrayList<ChainFilter<Hit>> getFilters() {
        return filters;
    }

    protected String getFileNameSuffix(){
        return fileSuffix;
    }

    @Override
    public ArtifactSubFolder getArtifactSubFolder() {
        return ArtifactSubFolder.DEMOGRAPHIC_REPORT;
    }

    @Override
    public boolean execute(Collection<Hit> hitCollection) throws Exception {
        // 1. create workbook
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet();


        // 2. write header
       XSSFRow header = sheet.createRow(0);
        writeHeader(header, demographicExtractors);



        // 3. write filters
        int rowIndex = 1;
        ArrayList<ChainFilter<Hit>> filters = getFilters();
        for (ChainFilter<Hit> filter : filters) {
            XSSFRow row = sheet.createRow(rowIndex++);
            Collection<Hit> filtered = FilterUtil.filterHits(hitCollection, filter);

            int cellIndex = 0;
            // header
            row.createCell(cellIndex++).setCellValue(filter.getName());
            row.createCell(cellIndex++).setCellValue(filtered.size());

            // values
            writeMeanValues(row, cellIndex, filtered, demographicExtractors);
        }

        return writeToFile(workbook);
    }

    private void writeMeanValues(XSSFRow row, int cellIndexOffset, Collection<Hit> filtered,
                                 List<HitWrapperExtractor<?, ? extends Number>> valueExtractors) {
        int cellIndex = cellIndexOffset;
        for (HitWrapperExtractor valueExtractor : valueExtractors) {
            row.createCell(cellIndex++).setCellValue(ListUtil.mean(filtered, valueExtractor));
        }

    }

    private void writeHeader(XSSFRow row, List<HitWrapperExtractor<?, ? extends Number>> valueExtractors) {
        int cellIndex = 0;
        row.createCell(cellIndex++).setCellValue("filter");
        row.createCell(cellIndex++).setCellValue("num Of plyers");
        for (HitWrapperExtractor valueExtractor : valueExtractors) {
            row.createCell(cellIndex++).setCellValue(valueExtractor.getName());
        }

    }


    private ChainFilter<Hit> f_all = new ChainFilter<Hit>("all") {
        @Override
        public boolean accept(Hit hit) {
            return true;
        }
    };

    private ChainFilter<Hit> f_age_L_30 = new ChainFilter<Hit>("age > 30") {
        @Override
        public boolean accept(Hit hit) {
            return QValueExtractor.age.getValue(hit.questionnaireRecord) > 30;
        }
    };

    private ChainFilter<Hit> f_age_SE_30 = new ChainFilter<Hit>("age <= 30") {
        @Override
        public boolean accept(Hit hit) {
            return QValueExtractor.age.getValue(hit.questionnaireRecord) <= 30;
        }
    };

    private ChainFilter<Hit> f_female = new ChainFilter<Hit>("female") {
        @Override
        public boolean accept(Hit hit) {
            return QValueExtractor.female.getValue(hit.questionnaireRecord) == 1;
        }
    };

    private ChainFilter<Hit> f_male = new ChainFilter<Hit>("male") {
        @Override
        public boolean accept(Hit hit) {
            return QValueExtractor.male.getValue(hit.questionnaireRecord) == 1;
        }
    };

    private ChainFilter<Hit> f_minorOnly = new ChainFilter<Hit>("minor only") {
        @Override
        public boolean accept(Hit hit) {
            List<Game> gl = hit.gameList;
            if (gl == null && gl.size() != 3) {
                return false;
            }
            for (int i = 1; i < gl.size(); i++) {
                Game game = gl.get(i);
                if (GameValueExtractor.moderate.getValue(game) > 0 || GameValueExtractor.severe.getValue(game) > 0) {
                    return false;
                }
            }
            return true;
        }
    };

    private ChainFilter<Hit> f_maintenanceToken = new ChainFilter<Hit>("maintenance done") {
        @Override
        public boolean accept(Hit hit) {
            List<Game> gl = hit.gameList;
            if (gl == null && gl.size() != 3) {
                return false;
            }
            for (int i = 1; i < gl.size(); i++) {
                Game game = gl.get(i);
                if (GameValueExtractor.maintenance.getValue(game) == 0) {
                    return false;
                }
            }
            return true;
        }
    };








}
